'''Hooks for calculating rankings and grades'''
import models
import random

from django import http
def calculate(sub):
    '''Calculates the score of a submission if all grades have been 
    submitted'''
    sub_grades = models.Grades.objects.filter(submission=sub)
    if not submission_is_complete(sub_grades):
        return
    calc_grade(sub, sub_grades)
    calc_ranking(sub, sub_grades)

def submission_is_complete(sub_grades):
    return len([i for i in sub_grades if i.grade == -1]) == 0

def calc_grade(sub, sub_grades):
    '''Calculate grade and save it to submission.  Return grade'''
    professors = [i for i in sub_grades if 
            models.UserProfile.objects.get(user=i.user).type=="Professor"]
    if len(professors) > 0:
        grade = 0
        for i in professors:
            grade += i.grade
        grade /= len(professors)
    else:
        total_rep = 0
        points = 0
        for grade in sub_grades:
            rep = models.UserProfile.objects.get(user=grade.user).ranking
            points += rep * grade.grade
            total_rep += rep
        grade = points/tota_rep
    sub.finalGrade = grade
    sub.save()

def calc_ranking(sub, sub_grades):
    '''Find user with highest reputation'''
    '''starts with the user submitted grade'''
    profile = models.UserProfile.objects.get(user=sub.student)
    highrank = profile.ranking
    highgrade = sub.selfGrade
    highuser = profile

    for grade in sub_grades:
        profile = models.UserProfile.objects.get(user=grade.user)
        if profile.ranking > highrank:
            highrank = profile.ranking
            highgrade = grade.grade
            highuser = profile
    
    '''Calculate new rankings'''
    for grade in sub_grades:
        if grade.grade is not highgrade:
            d = abs(highgrade - grade.grade)
            if d <= 7:
                N = 3/70 * d + 1/2
            else:
                N = -1/66 * (d - 7)
            profile = models.UserProfile.objects.get(user=grade.user)
            profile.ranking += N*(highrank - profile.ranking)
            profile.save()
            
            
    '''Special case for self grade rank calculation'''
    if highuser is not sub.student: 
        d = abs(highgrade - sub.selfGrade)
        if d <= 7:
            N = -3/70 * d + 1/2
        else:
            N = -1/66 * (d - 7)
        profile = models.UserProfile.objects.get(user=sub.student)
        profile.ranking += N*(highrank - profile.ranking)
        profile.save()


def distribute_submissions(assignment):
    THRESHOLD = 6
    subs = models.Submissions.objects.filter(assignment=assignment)
    if not len(subs) == len(models.UserProfile.objects.filter(type="Student")):
        return
    assigned = {}
    trusted = [i.user for i in models.UserProfile.objects.all()
            if i.ranking > 6]

    allgraders = [i.user for i in models.UserProfile.objects.all()]
    for i in allgraders:
        if i not in assigned:
            assigned[i] = []

    for sub in subs:
        while True:
            grader = random.choice(trusted)
            if grader != sub.student and sub not in assigned[grader] and len(
                    assigned[grader]) <= (len(subs)/len(trusted)):
                assigned[grader].append(sub)
                break

    for sub in subs:
        assigned_to = 0
        while assigned_to < 2:
            grader = random.choice(allgraders)
            if grader != sub.student and sub not in assigned[grader] and len(
                    assigned[grader]) < 3:
                assigned[grader].append(sub)
                assigned_to += 1

    for user in assigned:
        for sub in assigned[user]:
            grade = models.Grades(submission=sub, user=user, grade=-1, 
                    comments="")
            grade.save()

def check_prof(user):
    if models.UserProfile.objects.get(user=user).type != "Professor":
        raise http.Http404
